package com.atguigu.demojuc.chap06;

import java.util.concurrent.*;

/**
 * Runnable接口：
 *  弊端
 *      run()没有返回结果，不能声明抛异常,来自于java.lang包
 */
class MyRunnable implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "\t MyRunnable - run()" + "---come in");
    }
}

/**
 * Callable接口：
 *      优势：
 *          call()方法有返回结果，可以声明异常。对Runnable接口run()进行增强。
 */
class MyCallable implements Callable<Integer>{
    @Override
    public Integer call() throws Exception {
        try {
            int i = 1/0;
            System.out.println(Thread.currentThread().getName() + "\t MyCallable - call()" + "---come in");
            TimeUnit.SECONDS.sleep(5);
        } catch (Exception e) {
            throw new RuntimeException("MyCallable call() - 异常");
        }
        return 100;
    }
}

public class CallableDemo {
    public static void main(String[] args) {
/*        MyRunnable myRunnable = new MyRunnable();

        Thread t1 = new Thread(myRunnable);
        t1.setName("t1");
        t1.start();

        Thread t2 = new Thread(myRunnable);
        t2.setName("t2");
        t2.start();*/

/*        MyCallable myCallable = new MyCallable();
        //如果需要启动两次线程，需要创建两个FutureTask对象。Callable对象只需要创建一个。
        FutureTask futureTask1 = new FutureTask<>(myCallable);
        FutureTask futureTask2 = new FutureTask<>(myCallable);

        Thread t3 = new Thread(futureTask1); //不能直接传Callable类型参数。但是可以接收Runnable类型参数。而FutureTask 实现了 Runnable 接口。
        t3.setName("t3");
        t3.start();

        Thread t4 = new Thread(futureTask2); //不能直接传Callable类型参数。但是可以接收Runnable类型参数。而FutureTask 实现了 Runnable 接口。
        t4.setName("t4");
        t4.start();*/

        MyCallable myCallable = new MyCallable();
        //FutureTask<V> implements RunnableFuture<V>
        //RunnableFuture<V> extends Runnable, Future<V>
        FutureTask<Integer> futureTask1 = new FutureTask<>(myCallable);

        Thread t3 = new Thread(futureTask1);
        t3.setName("t3");
        t3.start(); //执行子线程任务，异步执行，主线程任务，可以根据情况执行。

        try {

            System.out.println(Thread.currentThread().getName() + "\t" + "---come in"); //main线程任务,在get()方法前不用被阻塞,异步执行。

            //TimeUnit.SECONDS.sleep(2);
            /*boolean cancel = futureTask1.cancel(true); //取消任务。任务没有被完成，需要终止。
            System.out.println("cancel = " + cancel);
            boolean cancelled = futureTask1.isCancelled(); //任务是否被终止
            if(cancelled){
                System.out.println("cancelled = " + cancelled);
            }*/

            while (!futureTask1.isDone()){ //任务没完成，睡觉等待
                Thread.sleep(200);
                System.out.println("waiting...");
            }

            //java.util.concurrent.CancellationException 任务取消无法获取结果的，会得到取消任务异常。
            Integer result = futureTask1.get(); // 阻塞方法，等待Callable中call()方法执行完成，获取call()方法的返回结果,这个结果封装在FutureTask对象中。
            // 阻塞方法，等待固定时间，如果Callable中call()方法执行超过这个时间，报java.util.concurrent.TimeoutException
            //Integer result = futureTask1.get(3,TimeUnit.SECONDS);
            System.out.println("result = " + result);


            //result = futureTask1.get(); //可以重复获取结果，都是同一个结果。
            //System.out.println("result2 = " + result);


            System.out.println(Thread.currentThread().getName() + "\t" + "---come in"); //main线程任务,在get()方法后,需要等子线程任务完成，才会执行主任务。

        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } catch (ExecutionException e) {  //get方法返回的异常，即：call()方法抛的异常被get()方法捕获后，转换为ExecutionException异常抛出。
            //throw new RuntimeException(e);
            e.printStackTrace();
        } /*catch (TimeoutException e) {
            throw new RuntimeException(e);
        }*/

    }
}
